package cn.dengta.context.config;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import cn.dengta.common.alarm.dingtalk.CacheBugWarnExpiredService;
import cn.dengta.common.context.Context;
import cn.dengta.common.util.SpringUtil;
import cn.dengta.webapp.base.util.MDCUtil;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import me.codeplayer.util.StringUtil;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.*;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * @see cn.dengta.common.dao.MyBatisConfiguration
 * @see cn.dengta.common.redis.RedisConfiguration
 */
@Configuration
@MapperScan(Context.BASE_DAO_PACKAGE)
@Slf4j
public class GlobalConfig {

	static TaskExecutor taskExecutor;

	@ConditionalOnProperty(name = "warn.service.impl", havingValue = "caffeine")
	@Bean
	public CacheBugWarnExpiredService bugWarnExpiredService() {
		final CaffeineCacheManager cacheManager = new CaffeineCacheManager();
		final Caffeine<Object, Object> caffeine = Caffeine.newBuilder()
				.initialCapacity(32)
				.maximumSize(512)
				.expireAfterWrite(60, TimeUnit.SECONDS);
		cacheManager.setCaffeine(caffeine);
		return new CacheBugWarnExpiredService(cacheManager);
	}

	@Bean(name = SpringUtil.TASK_EXECUTOR_BEAN_NAME)
	@Lazy
	public TaskExecutor defaultTaskExecutor() {
		return taskExecutor("Common-Task-Pool-");
	}

	/** 核心任务执行 */
	@Bean(name = "coreTaskExecutor")
	@Lazy
	public TaskExecutor coreTaskExecutor() {
		return taskExecutor("Core-Task-Pool-");
	}

	private static TaskExecutor taskExecutor(String name) {
		ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
		pool.setThreadNamePrefix(name);
		int coreCount = Runtime.getRuntime().availableProcessors();
		int min = Math.min(coreCount >> 1, 1);
		pool.setCorePoolSize(min);
		// 需要考虑 任务 的IO类型
		pool.setMaxPoolSize(coreCount * 2 + 2);
		pool.setQueueCapacity(1024);
		pool.setKeepAliveSeconds(300);
		pool.setWaitForTasksToCompleteOnShutdown(true);
		pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		return pool;
	}

	/**
	 * 国际化配置
	 */
	@Bean
	public ResourceBundleMessageSource messageSource() {
		final ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
		ms.setBasenames("base", "messages");
		ms.setUseCodeAsDefaultMessage(true);
		ms.setFallbackToSystemLocale(false);
		ms.setDefaultEncoding("UTF-8");
		return ms;
	}

	/**
	 * 分布式定时任务 XXL-JOB 配置
	 */
	@ConditionalOnProperty("xxl-job.admin-addresses")
	@ConfigurationProperties(prefix = "xxl-job")
	@Bean
	public XxlJobSpringExecutor xxlJobExecutor() {
		log.info(">>>>>>>>>>> xxl-job config init.");
		return new XxlJobSpringExecutor();
	}

	public static TaskExecutor getTaskExecutor() {
		if (taskExecutor == null) {
			taskExecutor = SpringUtil.getBean("coreTaskExecutor", TaskExecutor.class);
		}
		return taskExecutor;
	}

	/** 异步允许核心业务任务 */
	public static void asyncCoreTaskRun(Runnable run) {
		getTaskExecutor().execute(MDCUtil.wrapParentTraceId(run));
	}

}
